package com.linkdood.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linkdood.app.domain.Account;
import com.linkdood.app.domain.DoodUser;
import com.linkdood.app.domain.User;
import com.linkdood.app.domain.UserData;
import com.linkdood.app.exception.InvalidParamException;
import com.linkdood.app.exception.UserNotFoundException;
import com.linkdood.app.mapper.UserMapper;
import com.linkdood.app.service.DdioService;
import com.linkdood.app.service.ThirdPartyService;
import com.linkdood.app.service.UserDataService;
import com.linkdood.app.service.UserService;
import com.linkdood.app.service.dto.DoodFriendsDTO;
import com.linkdood.app.utils.PinYinUtil;
import com.linkdood.app.vm.AccountVM;
import com.linkdood.app.vm.UserVM;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Optional;

/**
 * user
 * @author YunJ
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final DdioService ddioService;

    private final ThirdPartyService thirdPartyService;

    private final UserDataService userDataService;

    public UserServiceImpl(DdioService ddioService, ThirdPartyService thirdPartyService, UserDataService userDataService) {
        this.ddioService = ddioService;
        this.thirdPartyService = thirdPartyService;
        this.userDataService = userDataService;
    }


    // FIXME 多表联合分页查询，暂时使用 Mybatis 旧版 XML 格式，以后优化
    @Override
    public Page<UserVM> pageUsers(String displayName, String phone, String sourceId, String orgId, Page<Account> page) {
        log.debug("getUserPage() : displayName={}, phone={}, sourceId={}, orgId={}", displayName, phone, sourceId, orgId);
        Page<UserVM> accountPage = new Page<>();
        // 分别单独查询总数和分页内容
        Long accountTotal = getBaseMapper().countUserAccountPageByNameAndPhone(displayName, phone, sourceId, orgId);
        if (accountTotal == 0L) {
            accountPage.setTotal(0L);
            return accountPage;
        }
        Long pageSkip = (page.getCurrent() - 1) * page.getSize();
        List<UserVM> accountList = getBaseMapper().listUserAccountPageByNameAndPhone(displayName, phone, sourceId, orgId, pageSkip, page.getSize());

        // 拼接
        accountPage.setTotal(accountTotal);
        accountPage.setSize(page.getSize());
        accountPage.setRecords(accountList);

        return accountPage;
    }

    @Override
    public Page<UserVM> pageByNameAndPhoneAndNoRoles(String displayName, String phone, List<String> noRoles, Page<User> page) {
        String roles = null;
        if (!CollectionUtils.isEmpty(noRoles)) {
            roles = StringUtils.join(noRoles, ",");
        }
        log.info("pageByNameAndPhoneAndNoRoles() : displayName={}, phone={}, noRoles={}", displayName, phone, roles);
        return getBaseMapper().pageByNameAndPhoneAndNoRoles(displayName, phone, roles, page);
    }

    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public List<DoodFriendsDTO> listFriends(AccountVM userAccount) {
        return ddioService.listAllFriends(userAccount);
    }

    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public Page<User> pageAllUsers(LambdaQueryWrapper<User> queryWrapper, Page<User> page) {
        return this.page(page, queryWrapper);
    }

    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public Integer countUser(String thirdPartyId) {
        return lambdaQuery().eq(User::getThirdPartyId, thirdPartyId)
                .count();
    }

    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public Optional<User> getBySourceId(String thirdPartyId, String sourceId) {
        log.debug("getBySourceId() : thirdPartyId={}, sourceId={}", thirdPartyId, sourceId);
        return lambdaQuery().eq(User::getThirdPartyId, thirdPartyId)
                .eq(User::getSourceId, sourceId).oneOpt();
    }

    @Override
    public User saveOrUpdateByDoodId(String doodId, String userToken) {
        // 从豆豆获取用户详情
        List<DoodUser> doodUsers = ddioService.listUserInfoByUserIds(new String[]{doodId});
        log.debug("用户的 userID 为 = {}, 从豆豆获取的用户详情 = {}", doodId, doodUsers.toString());
        Optional<DoodUser> user = doodUsers.stream()
            .filter(doodUser -> doodUser.getUserID().equals(doodId))
            .findFirst();

        if (user.isPresent()) {
            // 用户数据保存或更新
            DoodUser doodUser = user.get();
            // FIXME ZZW 倘若是 dood 登录, 目前后端没法直接获取 userToken， 详见:好社工 issue #77 说明
            doodUser.setAccount(userToken);
            return saveOrUpdate(doodUser);
        } else {
            throw new UserNotFoundException();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public User saveOrUpdate(DoodUser doodUser) {
        log.debug("saveOrUpdate, doodUser = {}", doodUser);
        if (doodUser == null) {
            throw new InvalidParamException();
        }

        // 保存 user 数据
        User user = new User();
        Optional<User> oldUser = getBySourceId(thirdPartyService.getDefaultThirdParty().getId(), doodUser.getUserID());
        if (oldUser.isPresent()) {
            log.debug("用户 {} 对应的在系统中的用户： oldUser = {}", doodUser.getUserID(), oldUser);
            user = oldUser.get();
        }
        user.setThirdPartyId(thirdPartyService.getDefaultThirdParty().getId());
        user.setDirty(false);
        user.setDisplayName(doodUser.getName());
        user.setSourceDeleted(false);
        user.setSourceId(doodUser.getUserID());
        saveOrUpdate(user);

        // 保存 userData 数据
        UserData userData = new UserData();
        Optional<UserData> oldUserData = userDataService.getByUserId(user.getId());
        if (oldUserData.isPresent()) {
            userData = oldUserData.get();
        }
        userData.setAccount(doodUser.getAccount());
        userData.setBirthday(doodUser.getBirthday());
        userData.setFirstPinYin(PinYinUtil.getFirstPinyin(doodUser.getName()));
        userData.setPortraitUrl(doodUser.getPortraitURL());
        userData.setName(doodUser.getName());
        userData.setPhoneNums(doodUser.getPhoneNums());
        userData.setSex(doodUser.getSex());
        userData.setUserId(user.getId());

        log.debug("saveUserData, userData = {}", userData);
        userDataService.saveOrUpdate(userData);
        return user;
    }

    @Override
    public Optional<User> getUserByDoodId(String doodId) {
        return lambdaQuery().eq(User::getSourceId, doodId).oneOpt();
    }
}
